package com.zhengsr.drawbroad;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by zhengshaorui on 2017/12/3.
 * csdn: http://blog.csdn.net/u011418943
 */

public class BroadView extends View {
    private static final String TAG = "BroadView";
    private Paint mPaint;
    private Path mPath;
    private Bitmap mBitmap;
    private Canvas mCanvas;
    private float mLastX,mLastY;
    private Context mContext;
    private Paint mEraserPaint;
    private int mMode;
    private boolean isReDoUndo;

    private List<DrawingInfo> mUndoDrawInfo = new ArrayList<>();
    private List<DrawingInfo> mRedoDrawInfo = new ArrayList<>();
    public BroadView(Context context) {
        this(context,null);
    }

    public BroadView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public BroadView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        setClickable(true);
        init(context,attrs);
    }

    private void init(Context context,AttributeSet attrs) {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setFilterBitmap(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(10);
        mPaint.setColor(Color.RED);

        mEraserPaint = new Paint();
        mEraserPaint.setAntiAlias(true);
        mEraserPaint.setFilterBitmap(true);
        mEraserPaint.setStyle(Paint.Style.STROKE);
        mEraserPaint.setAlpha(0);
        mEraserPaint.setColor(Color.TRANSPARENT);
        mEraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        mEraserPaint.setStrokeWidth(20);

        DisplayMetrics dm = new DisplayMetrics();
        ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
        mBitmap = Bitmap.createBitmap(dm.widthPixels,dm.heightPixels,
                Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);


    }

    @Override
    protected void onDraw(Canvas canvas) {

            canvas.drawBitmap(mBitmap,0,0,mPaint);

      //  canvas.drawPath(mPath,mPaint);


    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                drawDown(event.getX(),event.getY());

                break;
            case MotionEvent.ACTION_MOVE:
                drawMove(event.getX(),event.getY());

                break;
            case MotionEvent.ACTION_UP:
                drawUp();
                break;
            default:
                break;
        }
        return true;
    }




    private void drawDown(float x, float y){
        if (mPath == null){
            mPath = new Path();
        }

        mLastX = x;
        mLastY = y;
        mPath.moveTo(x,y);
        //mCanvas.drawPoint(x,y,mPaint); //画点
        //invalidate();
    }

    private void drawMove(float x, float y) {
        //贝塞尔曲线画线
        mPath.quadTo(mLastX,mLastY,(x+mLastX)/2,(y+mLastY)/2);
        isReDoUndo = false;
        if (mMode == 1) {
            mCanvas.drawPath(mPath, mEraserPaint);
        }else{
            mCanvas.drawPath(mPath, mPaint);
        }
        invalidate();
        mLastX = x;
        mLastY = y;
    }

    private void drawUp() {

        saveDrawInfo();
        //由于使用了reset()，它会把path内部的数据清除，所以，我们需要用一个类来保存，用list则没有的
        mPath.reset();


    }

    private void saveDrawInfo() {
        Path cachePath = new Path(mPath);
        PathDrawingInfo info = new PathDrawingInfo();
        if (mMode == 1) {
            info.paint = new Paint(mEraserPaint);
        }else{
            info.paint = new Paint(mPaint);
        }
        info.path = cachePath;

        mUndoDrawInfo.add(info);
    }

    public void setMode(int mode) {
        mMode = mode;
    }


    private abstract static class DrawingInfo {
        Paint paint;
        abstract void draw(Canvas canvas);
    }

    private static class PathDrawingInfo extends DrawingInfo{

        Path path;

        @Override
        void draw(Canvas canvas) {
            canvas.drawPath(path, paint);
        }
    }


    /**
     * 清楚屏幕
     */
    public void clear(){
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        mCanvas.drawPaint(mPaint);
        invalidate();
        mPaint.setXfermode(null);
    }


    public void reset(){
        clear();
        mUndoDrawInfo.clear();
        mUndoDrawInfo.clear();
    }

    public void redo() {
        if (!mRedoDrawInfo.isEmpty()){
            int count = mRedoDrawInfo.size();
            DrawingInfo info = mRedoDrawInfo.get(count - 1);
            mUndoDrawInfo.add(info);
            mRedoDrawInfo.remove(count - 1);
            reDraw();
        }else{
            Toast.makeText(mContext, "nothing can redo", Toast.LENGTH_SHORT).show();
        }
    }

    public void undo() {
        if (!mUndoDrawInfo.isEmpty()){
            clear();//清屏

            int count = mUndoDrawInfo.size();
            DrawingInfo info = mUndoDrawInfo.get(count - 1);
            mRedoDrawInfo.add(info);
            mUndoDrawInfo.remove(count -1);
            reDraw();

        }else{
            Toast.makeText(mContext, "nothing can undo", Toast.LENGTH_SHORT).show();
        }
    }

    private void reDraw() {
        for (DrawingInfo info : mUndoDrawInfo) {
            isReDoUndo = true;
            info.draw(mCanvas);
        }
        invalidate();
    }
}
